package org.nanowrimo.ws;

import org.nanowrimo.ws.domain.RegionSummary;
import org.nanowrimo.ws.domain.UserSummary;
import org.nanowrimo.ws.domain.WordCountSummary;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.text.MessageFormat;

/**
 * Java Client to the <a href="http://www.nanowrimo.org/">NaNoWriMo</a> (National Novel Writing Month) word count webservice API
 *
 * @author Paul S. Hawke
 * @version 1.0
 */
public class NanowrimoWebServiceAPI {

  /**
   * Retrieve basic summary information for a given user.  This will include their name, user ID and overall word count.
   *
   * @param userID the numeric user ID for a NaNoWriMo user
   * @return <code>UserSummary</code> object containing the user details.<br>Note: the
   *         <i>entries</i> property of the <code>UserSummary</code> object will be null.
   * @see org.nanowrimo.ws.domain.UserSummary
   */
  public WordCountSummary getUserSummary(int userID) {
    return getSummary(userID, ServiceApiConstants.USER_SUMMARY_URL, new UserWordCountHandler());
  }

  /**
   * Retrieve the basic details for a given Nanowrimo region.
   *
   * @param regionID the numeric ID for a Nanorwimo region
   * @return <code>RegionSummary</code> object containing the basic region details.<br><i>Note:</i>
   *         the <i>entries</i> property of the object will be null.
   * @see org.nanowrimo.ws.domain.RegionSummary
   */
  public WordCountSummary getRegionSummary(int regionID) {
    return getSummary(regionID, ServiceApiConstants.REGION_SUMMARY_URL, new RegionWordCountHandler());
  }

  /**
   * Retrieve basic summary information for a given user or region.  This will include the name, user ID and overall word count.
   *
   * @param itemID    the numeric user ID for a NaNoWriMo user / Region
   * @param urlFormat a <code>MessageFormat</code> string for the URL, giving the location of where to insert the ID
   * @param handler   the SAX content handler that will parse the response
   * @return <code>WordCountSummary</code> object containing the user / region details.
   * @see org.nanowrimo.ws.domain.WordCountSummary
   */
  public WordCountSummary getSummary(int itemID, String urlFormat, WordCountHandler handler) {
    String urlString = MessageFormat.format(urlFormat, new Integer(itemID));
    processWebserviceCall(urlString, handler);
    return handler.getSummary();
  }

  /**
   * Retrieve the basic user details plus wordcount history for a given user.
   *
   * @param userID the numeric user ID for a NaNoWriMo user
   * @return <code>UserSummary</code> object containing the user details plus history.
   *         The <i>entries</i> property of the <code>UserSummary</code> object will contain an
   *         array of <code>WordCountListEntry</code> objects.
   * @see org.nanowrimo.ws.domain.UserSummary
   * @see org.nanowrimo.ws.domain.WordCountListEntry
   */
  public UserSummary getUserHistory(int userID) {
    String urlString = MessageFormat.format(ServiceApiConstants.USER_HISTORY_URL, new Integer(userID));
    UserWordCountHandler handler = new UserWordCountHandler();
    processWebserviceCall(urlString, handler);
    return handler.getUserSummary();
  }

  /**
   * Retrieve the basic region details plus wordcount history for a given region.
   *
   * @param regionID the numeric ID for a Nanorwimo region
   * @return <code>RegionSummary</code> object containing the basic region details plus history.
   *         The <i>entries</i> property of the object will contain an array of
   *         <code>WordCountListEntry</code> objects.
   * @see org.nanowrimo.ws.domain.RegionSummary
   * @see org.nanowrimo.ws.domain.WordCountListEntry
   */
  public RegionSummary getRegionHistory(int regionID) {
    String urlString = MessageFormat.format(ServiceApiConstants.REGION_HISTORY_URL, new Integer(regionID));
    RegionWordCountHandler handler = new RegionWordCountHandler();
    processWebserviceCall(urlString, handler);
    return handler.getRegionSummary();
  }

  private void processWebserviceCall(String urlString, DefaultHandler handler) {
    try {
      Reader serverReader = getServerStreamReader(urlString);
      SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
      XMLReader reader = parser.getXMLReader();
      reader.setContentHandler(handler);
      reader.parse(new InputSource(serverReader));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  protected Reader getServerStreamReader(String urlString) throws IOException {
    return new InputStreamReader(new URL(urlString).openStream());
  }
}
